package com.gitee.wsl.ext.string.builder

import com.gitee.wsl.ext.number.HEX_RADIX
import com.gitee.wsl.ext.string.COMPLEX_UNICODE_LENGTH
import com.gitee.wsl.ext.string.SIMPLE_UNICODE_LENGTH
import com.gitee.wsl.ext.string.SIMPLE_UNICODE_PREFIX
import com.gitee.wsl.ext.string.appendCodePoint

infix operator fun <T>StringBuilder.plusAssign(element: T) {
    append(element)
}

fun buildString(block:StringBuilder.()->Unit):String{
    val ret = StringBuilder()
    block(ret)
    return ret.toString()
}

fun StringBuilder.capitalize(s: String): StringBuilder {
    if (s.length > 1 && s[1].isUpperCase()) {
        return append(s)
    }
    append(s.substring(0, 1).uppercase())
    append(s.substring(1))
    return this
}

//fun StringBuilder.appendCodePoint(codePoint:Int){
//    this.append(codePointToString(codePoint))
//}

/**
 * Escaping and converting unicode symbols for decoding
 *
 * @param fullString
 * @param marker
 * @param codeStartIndex
 * @param lineNo line number of a string
 * @return position of
 * @throws ParseException
 * @throws UnknownEscapeSymbolsException
 */
public fun StringBuilder.appendEscapedUnicode(
    fullString: String,
    marker: Char,
    codeStartIndex: Int,
    lineNo: Int
): Int {
    val nbUnicodeChars = if (marker == SIMPLE_UNICODE_PREFIX) {
        SIMPLE_UNICODE_LENGTH
    } else {
        COMPLEX_UNICODE_LENGTH
    }
    if (codeStartIndex + nbUnicodeChars > fullString.length) {
        val invalid = fullString.substring(codeStartIndex - 1)
        throw Exception("$lineNo:\\$invalid" )
    }
    val hexCode = fullString.substring(codeStartIndex, codeStartIndex + nbUnicodeChars)
    val codePoint = hexCode.toInt(HEX_RADIX)
    try {
        appendCodePoint(codePoint)
        //appendCodePointCompat(codePoint)
    } catch (e: IllegalArgumentException) {
        throw Exception("$lineNo:\\$marker$hexCode" )
    }
    return nbUnicodeChars
}

/**
 * An optimized way to replace all occurrences of [oldValue] with [newValue] in a [StringBuilder].
 * @return this builder
 */
fun StringBuilder.replace(
    oldValue: String,
    newValue: String,
) = apply {
    var index: Int
    while (indexOf(oldValue).also { index = it } >= 0) {
        replaceRange(index, index + oldValue.length, newValue)
    }
}

/**
 * Replaces the chars in a builder with the ones stored in the translation table. The indexes in the table refers to
 * the code points of the chars to be replaced.
 *
 * @param str   the string builder in which to replace the chars
 * @param table the translation table
 */
fun StringBuilder.translate( table: CharArray) {
    for (idx in 0 until length) {
        var ch = this[idx]
        if (ch.code < table.size) {
            ch = table[ch.code]
            this[idx] = ch
        }
    }
}


/**
 * Replaces the chars in a builder with the ones stored in the translation map.
 *
 * @param str the string builder in which to replace the chars
 * @param map the translation map
 */
fun StringBuilder.translate( map: Map<Char?, Char?>) {
    for (idx in 0 until length) {
        val ch = this[idx]
        val conversion = map[ch]
        if (conversion != null) this[idx] = conversion
    }
}